package gtpengine

import (
	"errors"
	"fmt"
	"gitee.com/larry_dev/gtpengine/gtpcommand"
	"regexp"
	"strconv"
	"strings"
)

type AnalyzeCB func(string)
type Output struct {
	StdOut strings.Builder
	ErrOut strings.Builder
	Errors strings.Builder
}
type GTPCommand struct {
	cmdClient *gtpcommand.CMDClient
	wait      chan error
	outSB     strings.Builder
	errSB     strings.Builder
	version   string
	showLog   bool
	isAnalyze bool
	OnAnalyze AnalyzeCB
}

func (g *GTPCommand) Version() float64 {
	v, _ := strconv.ParseFloat(g.version, 64)
	return v
}
func (g *GTPCommand) Result(cmd string) (gtpcommand.Result, error) {
	<-g.wait
	result, err := g.parseCommand()
	return gtpcommand.Result{
		Command: cmd,
		Result:  result,
		ErrOut:  g.errSB.String(),
	}, err
}

func (g *GTPCommand) Start(cmd string) error {
	g.errSB.Reset()
	g.outSB.Reset()
	g.wait = make(chan error)
	return g.cmdClient.PostCommand(cmd, false)
}

func (g *GTPCommand) StdErr(line string) {
	g.errSB.WriteString(line)

}
func (g *GTPCommand) parseCommand() (string, error) {
	result := g.outSB.String()
	regParse := regexp.MustCompile(`([=?]).*\n*`)
	result = regParse.FindString(result)
	res := strings.Split(result, "")
	l := len(res)
	if l > 0 {
		if res[l-1] == "\n" {
			result = strings.Join(res[:l-1], "")
		}
		if len(result) == 0 {
			return "", errors.New("ERROR length=0")
		}
		if res[0] == "=" {
			return strings.TrimSpace(strings.Join(res[2:], "")), nil
		}
		if res[0] == "?" {
			return "", errors.New(strings.Join(res[2:], ""))
		}
	}
	return "", errors.New("ERROR: Unrecognized answer: " + result)
}

func (g *GTPCommand) StdOut(line string) {
	g.logOut("receive", line)
	g.outSB.WriteString(line)
	if g.isAnalyze {
		g.OnAnalyze(line)
	}
	if (strings.Contains(line, "=") && !g.isAnalyze) || strings.Contains(line, "?") {
		close(g.wait)
	}
}
func NewGTPCommand(client *gtpcommand.CMDClient, ops ...int) *GTPCommand {
	command := &GTPCommand{
		cmdClient: client,
		outSB:     strings.Builder{},
		errSB:     strings.Builder{},
	}
	client.Build(command)
	ver, err := command.SendCMD("version")
	if err == nil {
		command.version = ver.Result
	} else {
		command.version = "0"
	}
	return command
}
func (g *GTPCommand) ShowLog(flag bool) {
	g.showLog = flag
}

// 判断命令是否支持
func (g *GTPCommand) KnowCommand(cmd string) bool {
	value, err := g.SendCMD("known_command " + cmd)
	if err != nil {
		return false
	}
	if strings.ToLower(strings.TrimSpace(value.Result)) != "true" {
		return false
	}
	return true
}

// 设置贴目
func (g *GTPCommand) Komi(komi float64) (gtpcommand.Result, error) {
	return g.SendCMD(fmt.Sprintf("komi %v", komi))
}

// 设置棋盘大小
func (g *GTPCommand) BoardSize(size int) (gtpcommand.Result, error) {
	return g.SendCMD(fmt.Sprintf("boardsize %v", size))
}

// 获取AI落子
func (g *GTPCommand) GenMove(color string) (gtpcommand.Result, error) {
	color = strings.ToUpper(color)
	command := "genmove " + color
	return g.SendCMD(command)
}

// 人落子
func (g *GTPCommand) Move(color, coor string) (gtpcommand.Result, error) {
	color = strings.ToUpper(color)
	return g.SendCMD(fmt.Sprintf("play %s %s", color, coor))
}

// 加载SGF文件
func (g *GTPCommand) LoadSgf(file string) (gtpcommand.Result, error) {
	command := fmt.Sprintf("loadsgf %s", file)
	return g.SendCMD(command)
}

// 获取当前盘面形势判断
func (g *GTPCommand) FinalStatusList(cmd string) (gtpcommand.Result, error) {
	command := fmt.Sprintf("final_status_list %s", cmd)
	return g.SendCMD(command)
}

// 设置AI级别
func (g *GTPCommand) SetLevel(seed int) (gtpcommand.Result, error) {
	command := fmt.Sprintf("level %d", seed)
	return g.SendCMD(command)
}

// 设置AI随机数
func (g *GTPCommand) SetRandomSeed(seed int) (gtpcommand.Result, error) {
	command := fmt.Sprintf("set_random_seed %d", seed)
	return g.SendCMD(command)
}

// 显示棋盘
func (g *GTPCommand) ShowBoard() (gtpcommand.Result, error) {
	return g.SendCMD("showboard")
}

// 清空棋盘
func (g *GTPCommand) ClearBoard() (gtpcommand.Result, error) {
	return g.SendCMD("clear_board")
}

//打印SGF
func (g *GTPCommand) PrintSgf() (gtpcommand.Result, error) {
	return g.SendCMD("printsgf")
}

// 设置时间规则
func (g *GTPCommand) TimeSetting(baseTime, byoTime, byoStones int) (gtpcommand.Result, error) {
	return g.SendCMD(fmt.Sprintf("time_settings %d %d %d", baseTime, byoTime, byoStones))
}

// 设置KGS time
func (g *GTPCommand) KGSTimeSetting(mainTime, readTime, readLimit int) (gtpcommand.Result, error) {
	return g.SendCMD(fmt.Sprintf("kgs-time_settings byoyomi %d %d %d", mainTime, readTime, readLimit))
}

//获取结果
func (g *GTPCommand) FinalScore() (gtpcommand.Result, error) {
	return g.SendCMD("final_score")
}

//悔棋
func (g *GTPCommand) Undo() (gtpcommand.Result, error) {
	return g.SendCMD("undo")
}

//设置时间
func (g *GTPCommand) TimeLeft(color string, mainTime, stones int) (gtpcommand.Result, error) {
	return g.SendCMD(fmt.Sprintf("time_left %s %d %d", color, mainTime, stones))
}

func (g *GTPCommand) Analyze(t int) (gtpcommand.Result, error) {
	return g.SendCMD(fmt.Sprintf("lz-analyze %d", t), true)
}
func (g *GTPCommand) Name() (gtpcommand.Result, error) {
	return g.SendCMD("name")
}

//退出
func (g *GTPCommand) Quit() (gtpcommand.Result, error) {
	r, err := g.SendCMD("Quit")
	g.cmdClient.Close()
	return r, err
}

// 方式自定义命令
func (g *GTPCommand) SendCMD(cmd string, params ...bool) (gtpcommand.Result, error) {
	is := false
	if len(params) > 0 {
		is = params[0]
	}
	if !is && g.isAnalyze {
		close(g.wait)
		g.isAnalyze = false
	}
	g.isAnalyze = is
	g.logOut("send", cmd)
	err := g.Start(cmd)
	if err != nil {
		return gtpcommand.Result{Command: cmd}, err
	}
	return g.Result(cmd)
}

var (
	green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
	reset = string([]byte{27, 91, 48, 109})
)

func (g *GTPCommand) logOut(event, data string) {
	if g.showLog {
		fmt.Printf("%s%s:%s%s\n", green, event, reset, data)
	}
}
